前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • JavaScript Part 1

    • Ajax总结篇
    • Canvas 绘制八大行星
    • DOM编程之API学习总结篇
    • JavaScript事件机制
    • JavaScript代码片段100个
    • JavaScript作用域分析总结
    • JavaScript原型链回顾
    • JavaScript及jQuery中的各种宽高属性图解
    • JavaScript工程项目的一系列最佳实践
    • JavaScript常用API合集
    • JavaScript数组、字符串、对象常用方法
    • JavaScript数组方法总结篇
    • JavaScript深浅拷贝
    • JavaScript运动框架之速度时间版本
    • JavaScript运行机制Event Loop
    • JavaScript防抖节流原理
    • Javascript中的复制粘贴功能
    • Javascript数组详解
    • OOP之原型与原型链
    • Object.defineProperty详解
    • V8源码浅析JS数组常见方法
    • await 在 forEach 中不生效解决方案
    • iframe+表单跨域提交POST请求
    • javascript笔记总结篇
    • 业务中处理数据结构常用的JS方法
    • 作用域
    • 你真的掌握变量和类型了吗
    • 前后端分离之数据Mock
    • 原型与原型链
    • 原生JS补给(上)
    • 如何写出一个惊艳面试官的深拷贝
    • 带你填一些JS容易出错的坑
    • 彻底弄懂 JavaScript 执行机制
    • 执行上下文 执行栈
    • 正则回顾总结
    • 正则基础知识
    • 正则完整篇
    • 正则表达式
    • 浅析Promise原理
    • 浅谈JavaScript中的异步处理
    • 深拷贝 vs 浅拷贝
    • 聊一聊typeof instanceof 实现原理.
    • 聊一聊闭包
    • 高阶函数map reduce filter
  • JavaScript Part 2

  • CSS

  • HTML

  • Jquery

  • ES6

  • 小程序

  • Vue

  • React

  • 深入React

  • React Native

  • NodeJS

  • Angular

  • TypeScript

  • Webpack

  • 浏览器

  • 移动端

  • 前端工程化

  • Electron

  • HTTP

  • Nginx

  • Linux

  • 数据结构与算法

  • LeetCode算法题

  • 综合

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

浅析React children|博客系列

# 一、子组件

我们有一个组件 <Grid /> 包含了几个组件 <Row /> 。你可能会这么使用它

<Grid>
  <Row />
  <Row />
  <Row />
</Grid>
@前端进阶之旅: 代码已经复制到剪贴板

这三个 Row 组件都成为了 Grid 的 props.children 。使用一个表达式容器,父组件就能够渲染它们的子组件

class Grid extends React.Component {
  render() {
    return <div>{this.props.children}</div>
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

父组件也能够决定不渲染任何的子组件或者在渲染之前对它们进行操作。例如,这个 <Fullstop /> 组件就没有渲染它的子组件

class Fullstop extends React.Component {
  render() {
    return <h1>Hello world!</h1>
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

# 二、任何东西都能是一个child

React中的Children不一定是组件,它们可以使任何东西。例如,我们能够将上面的文字作为children传递我们的 <Grid /> 组件

<Grid>Hello world!</Grid>
@前端进阶之旅: 代码已经复制到剪贴板
  • JSX将会自动删除每行开头和结尾的空格,以及空行。它还会把字符串中间的空白行压缩为一个空格
  • 你也可以将多种类型的children完美的结合在一起:
<Grid>
  Here is a row:
  <Row />
  Here is another row:
  <Row />
</Grid>
@前端进阶之旅: 代码已经复制到剪贴板

# 三、child 的功能

  • 我们能够传递任何的JavaScript表达式作为children,包括函数

为了说明这种情况,以下是一个组件,它将执行一个传递过来的作为child的函数

class Executioner extends React.Component {
  render() {
    // See how we're calling the child as a function?
    //                        ↓
    return this.props.children()
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

你会像这样的使用这个组件

<Executioner>
  {() => <h1>Hello World!</h1>}
</Executioner>
@前端进阶之旅: 代码已经复制到剪贴板

# 四、操作children

从本质上来讲, props.children 可以使任何的类型,比如数组、函数、对象等

React提供了一系列的函数助手来使得操作children更加方便

# 4.1 循环

两个最显眼的函数助手就是 React.Children.map 以及 React.Children.forEach。它们在对应数组的情况下能起作用,除此之外,当函数、对象或者任何东西作为children传递时,它们也会起作用

class IgnoreFirstChild extends React.Component {
  render() {
    const children = this.props.children
    return (
      <div>
        {React.Children.map(children, (child, i) => {
          // Ignore the first child
          if (i < 1) return
          return child
        })}
      </div>
    )
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

<IgnoreFirstChild /> 组件在这里会遍历所有的children,忽略第一个child然后返回其他的

<IgnoreFirstChild>
  <h1>First</h1>
  <h1>Second</h1> // <- Only this is rendered
</IgnoreFirstChild>
@前端进阶之旅: 代码已经复制到剪贴板

在这种情况下,我们也可以使用``this.props.children.map 的方法。但将一个函数作为child传递过来将会发生什么呢?this.props.children` 会是一个函数而不是一个数组,接着我们就会产生一个error

然而使用 React.Children.map函数,无论什么都不会报错

<IgnoreFirstChild>
  {() => <h1>First</h1>} // <- Ignored 💪
</IgnoreFirstChild>
@前端进阶之旅: 代码已经复制到剪贴板

# 4.2 计数

因为this.props.children 可以是任何类型的,检查一个组件有多少个children是非常困难的。天真的使用 this.props.children.length ,当传递了字符串或者函数时程序便会中断。假设我们有个child:“Hello World!” ,但是使用 .length 的方法将会显示为12。

这就是为什么我们有 React.Children.count 方法的原因

class ChildrenCounter extends React.Component {
  render() {
    return <p>React.Children.count(this.props.children)</p>
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

无论时什么类型它都会返回children的数量

// Renders "1"
<ChildrenCounter>
  Second!
</ChildrenCounter>

// Renders "2"
<ChildrenCounter>
  <p>First</p>
  <ChildComponent />
</ChildrenCounter>

// Renders "3"
<ChildrenCounter>
  {() => <h1>First!</h1>}
  Second!
  <p>Third!</p>
</ChildrenCounter>
@前端进阶之旅: 代码已经复制到剪贴板

# 4.3 转换为数组

如果以上的方法你都不适合,你能将children转换为数组通过 React.Children.toArray 方法。如果你需要对它们进行排序,这个方法是非常有用的

class Sort extends React.Component {
  render() {
    const children = React.Children.toArray(this.props.children)
    // Sort and render the children
    return <p>{children.sort().join(' ')}</p>
  }
}
@前端进阶之旅: 代码已经复制到剪贴板
<Sort>
  // We use expression containers to make sure our strings
  // are passed as three children, not as one string
  {'bananas'}{'oranges'}{'apples'}
</Sort>
@前端进阶之旅: 代码已经复制到剪贴板

上例会渲染为三个排好序的字符串

# 4.4 执行单一child

如果你回过来想刚才的 <Executioner /> 组件,它只能在传递单一child的情况下使用,而且child必须为函数

class Executioner extends React.Component {
  render() {
    return this.props.children()
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

我们可以试着去强制执行 propTypes ,就像下面这样

Executioner.propTypes = {
  children: React.PropTypes.func.isRequired,
}
@前端进阶之旅: 代码已经复制到剪贴板

这会使控制台打印出一条消息,部分的开发者将会把它忽视。相反的,我们可以使用在 render 里面使用 React.Children.only

class Executioner extends React.Component {
  render() {
    return React.Children.only(this.props.children)()
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

这样只会返回一个child。如果不止一个child,它就会抛出错误,让整个程序陷入中断——完美的避开了试图破坏组件的懒惰的开发者

# 五、编辑children

我们可以将任意的组件呈现为children,但是任然可以用父组件去控制它们,而不是用渲染的组件。为了说明这点,让我们举例一个 能够拥有很多 RadioButton 组件的 RadiaGroup 组件

RadioButtons 不会从 RadioGroup 本身上进行渲染,它们只是作为children使用。这意味着我们将会有这样的代码

render() {
  return(
    <RadioGroup>
      <RadioButton value="first">First</RadioButton>
      <RadioButton value="second">Second</RadioButton>
      <RadioButton value="third">Third</RadioButton>
    </RadioGroup>
  )
}
@前端进阶之旅: 代码已经复制到剪贴板
  • 这段代码有一个问题。input 没有被分组
  • 为了把 input 标签弄到同组,必须拥有相同的name 属性。当然我们可以直接给每个RadioButton 的name 赋值
<RadioGroup>
  <RadioButton name="g1" value="first">First</RadioButton>
  <RadioButton name="g1" value="second">Second</RadioButton>
  <RadioButton name="g1" value="third">Third</RadioButton>
</RadioGroup>
@前端进阶之旅: 代码已经复制到剪贴板

# 5.1 改变children的属性

在RadioGroup 中我们将会添加一个叫做 renderChildren 的方法,在这里我们编辑children的属性

class RadioGroup extends React.Component {
  constructor() {
    super()
    // Bind the method to the component context
    this.renderChildren = this.renderChildren.bind(this)
  }

  renderChildren() {
    // TODO: Change the name prop of all children
    // to this.props.name
    return this.props.children
  }

  render() {
    return (
      <div className="group">
        {this.renderChildren()}
      </div>
    )
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

让我们开始遍历children获得每个child

renderChildren() {
  return React.Children.map(this.props.children, child => {
    // TODO: Change the name prop to this.props.name
    return child
  })
}
@前端进阶之旅: 代码已经复制到剪贴板

← 梳理Immutable常用API浅析React高阶组件HOC →

fe
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • JavaScript Part 1

    • Ajax总结篇
    • Canvas 绘制八大行星
    • DOM编程之API学习总结篇
    • JavaScript事件机制
    • JavaScript代码片段100个
    • JavaScript作用域分析总结
    • JavaScript原型链回顾
    • JavaScript及jQuery中的各种宽高属性图解
    • JavaScript工程项目的一系列最佳实践
    • JavaScript常用API合集
    • JavaScript数组、字符串、对象常用方法
    • JavaScript数组方法总结篇
    • JavaScript深浅拷贝
    • JavaScript运动框架之速度时间版本
    • JavaScript运行机制Event Loop
    • JavaScript防抖节流原理
    • Javascript中的复制粘贴功能
    • Javascript数组详解
    • OOP之原型与原型链
    • Object.defineProperty详解
    • V8源码浅析JS数组常见方法
    • await 在 forEach 中不生效解决方案
    • iframe+表单跨域提交POST请求
    • javascript笔记总结篇
    • 业务中处理数据结构常用的JS方法
    • 作用域
    • 你真的掌握变量和类型了吗
    • 前后端分离之数据Mock
    • 原型与原型链
    • 原生JS补给(上)
    • 如何写出一个惊艳面试官的深拷贝
    • 带你填一些JS容易出错的坑
    • 彻底弄懂 JavaScript 执行机制
    • 执行上下文 执行栈
    • 正则回顾总结
    • 正则基础知识
    • 正则完整篇
    • 正则表达式
    • 浅析Promise原理
    • 浅谈JavaScript中的异步处理
    • 深拷贝 vs 浅拷贝
    • 聊一聊typeof instanceof 实现原理.
    • 聊一聊闭包
    • 高阶函数map reduce filter
  • JavaScript Part 2

  • CSS

  • HTML

  • Jquery

  • ES6

  • 小程序

  • Vue

  • React

  • 深入React

  • React Native

  • NodeJS

  • Angular

  • TypeScript

  • Webpack

  • 浏览器

  • 移动端

  • 前端工程化

  • Electron

  • HTTP

  • Nginx

  • Linux

  • 数据结构与算法

  • LeetCode算法题

  • 综合